#include "ContractLoader.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDateTime>
#include "LogManager.h"
#include <QDebug>
ContractLoader::ContractLoader(QObject *parent)
    : QObject(parent)
{
    connect(&m_scheduleTimer, &QTimer::timeout, this, &ContractLoader::onScheduledUpdate);
    connect(&m_retryTimer, &QTimer::timeout, this, &ContractLoader::startUpdate);
}

ContractLoader::~ContractLoader()
{
    stop();
}

bool ContractLoader::init(const QString& configFile)
{
    m_configFile = configFile;
    
    if (!loadConfig(configFile)) {
        return false;
    }

    // 创建并初始化TrLoader
    m_loader = std::make_unique<TrLoader>();
    qDebug() << "m_loader: " << m_loader.get();
    // 连接信号
    connect(m_loader.get(), &TrLoader::instrumentsUpdated, this, &ContractLoader::onUpdateCompleted);
    connect(m_loader.get(), &TrLoader::error, this, &ContractLoader::onUpdateError);
    connect(m_loader.get(), &TrLoader::connected, this, &ContractLoader::onLoaderConnected);
    connect(m_loader.get(), &TrLoader::disconnected, this, &ContractLoader::onLoaderDisconnected);

    return true;
}

void ContractLoader::start()
{
    scheduleNextUpdate();
}

void ContractLoader::stop()
{
    m_scheduleTimer.stop();
    m_retryTimer.stop();
    if (m_loader) {
        m_loader->stop();
    }
}

bool ContractLoader::loadConfig(const QString& configFile)
{
    QFile file(configFile);
    if (!file.open(QIODevice::ReadOnly)) {
        MLOG_ERROR("loader", "Failed to open config file: {}", configFile.toStdString());
        return false;
    }
    QByteArray data = file.readAll();
    file.close();
    
    try {
        QJsonDocument doc = QJsonDocument::fromJson(data);
        QJsonObject root = doc.object();
        
        // 读取调度配置
        auto schedule = root["schedule"].toObject();
        m_updateTime = QTime::fromString(schedule["time"].toString(), "HH:mm:ss");
        
        auto retry = schedule["retry"].toObject();
        m_retryCount = retry["count"].toInt(3);
        m_retryInterval = retry["interval"].toInt(300);
        
        // 初始化CTP配置
        QMap<QString, QVariant> ctpConfig;
        auto ctp = root["ctp"].toObject();
        for (auto it = ctp.begin(); it != ctp.end(); ++it) {
            ctpConfig[it.key()] = it.value().toVariant();
        }

        if (!m_loader->init(ctpConfig)) {
            return false;
        }
        
        return true;
    }
    catch (const std::exception& e) {
        MLOG_ERROR("loader", "Failed to parse config: {}", e.what());
        return false;
    }
}

void ContractLoader::scheduleNextUpdate()
{
    QDateTime now = QDateTime::currentDateTime();
    QDateTime next = QDateTime(now.date(), m_updateTime);
    
    // 如果今天的更新时间已经过了，调度到明天
    if (now.time() >= m_updateTime) {
        next = next.addDays(1);
    }
    
    int msecs = now.msecsTo(next);
    m_scheduleTimer.start(msecs);
    
    MLOG_INFO("loader", "Next update scheduled at: {}", 
              next.toString("yyyy-MM-dd HH:mm:ss").toStdString());
}

void ContractLoader::onScheduledUpdate()
{
    m_currentRetry = 0;
    startUpdate();
}

void ContractLoader::startUpdate()
{
    if (m_updating) {
        return;
    }
    
    m_updating = true;
    m_retryTimer.stop();
    
    MLOG_INFO("loader", "Starting contract update...");
    m_loader->start();
}

void ContractLoader::retryUpdate()
{
    if (m_currentRetry >= m_retryCount) {
        MLOG_ERROR("loader", "Max retry count reached, giving up");
        m_updating = false;
        scheduleNextUpdate();
        return;
    }
    
    m_currentRetry++;
    MLOG_INFO("loader", "Retrying update in {} seconds (attempt {}/{})", 
              m_retryInterval, m_currentRetry, m_retryCount);
    
    m_retryTimer.start(m_retryInterval * 1000);
}

void ContractLoader::onUpdateCompleted()
{
    MLOG_INFO("loader", "Contract update completed successfully");
    m_updating = false;
    m_loader->stop();
    scheduleNextUpdate();
}

void ContractLoader::onUpdateError(const QString& error, int errorId)
{
    MLOG_ERROR("loader", "Update error: {} ({})", error.toStdString(), errorId);
    m_loader->stop();
    retryUpdate();
}

void ContractLoader::onLoaderConnected()
{
    MLOG_INFO("loader", "Connected to trading server");
}

void ContractLoader::onLoaderDisconnected(int reason)
{
    MLOG_WARN("loader", "Disconnected from trading server, reason: {}", reason);
    if (m_updating) {
        retryUpdate();
    }
} 